/*
 * Copyright (c) 2008, Xiong Yingfei, the University of Tokyo All rights
 * reserved.
 */
package ac.jp.u_tokyo.SyncLib;

import ac.jp.u_tokyo.SyncLib.util.Helper;

public class SetMember<T> extends StateSync
{
	public interface MemberTester<T>
	{
		boolean isMember(T v);
	}

	MemberTester<T> _tester;
	
	T _defaultValue;
	
	private T getValue() {
		return (T) getAttribute(0);
	}

	private void modifyValue(Mod mod) {
		modifyAttribute(0, mod);
	}

	public SetMember(MemberTester<T> tester, T defaultValue)
	{
		super(new Object[] {Helper.deepCopy(null)});
		_defaultValue = defaultValue;
		_tester = tester;
	}

//	public Object[] getInitialValues()
//	{
//		return new Object[] { _defaultValue };
//	}

	public int getParaCount()
	{
		return 1;
	}

	public Mod[] resynchronize(Object[] values, Mod[] modifications)
			throws SynchronizationFailedException
	{
		assert modifications[0] != null;
		T value = (T) modifications[0].apply(values[0]);
		if (!_tester.isMember(value))
		{
			Mod<Object> result = Value2Mod.findMod(values[0], _defaultValue);
			if (!result.isConflict(modifications[0]))
			{
				modifyValue(Value2Mod.findMod(getValue(), _defaultValue));
				return new Mod[] { result };
			}
			else
				throw new SynchronizationFailedException();
		}
		modifyValue(Value2Mod.findMod(getValue(), modifications[0].apply(values[0])));
		return modifications;
	}

	public Mod[] synchronize(Mod[] modifications)
			throws SynchronizationFailedException
	{
		assert modifications[0] != null;
		Mod<T> mod = modifications[0];
//		Mod<T> reverse = mod.getInverse(_value);
//		_value = mod.inPlaceApply(_value);
		if (!_tester.isMember(mod.apply(getValue())))
		{
			throw new SynchronizationFailedException();
		}
		modifyValue(mod);
		return modifications;
	}

}
